package org.jeecg.modules.iot.aliyun;

import org.jeecg.modules.iot.common.AppConfig;
import org.jeecg.modules.iot.message.Powerbank;
import org.jeecg.modules.iot.message.ReceivePopupSN;
import org.jeecg.modules.iot.message.ReceiveUpload;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class RentboxUtils {
    public static final String SEND_CHECK ="{\"cmd\":\"check\"}";
    public static final String SEND_CHECK_LOG ="{\"cmd\":\"check_log\"}";
    public static final String SEND_CHECK_ALL ="{\"cmd\":\"check_all\"}";
    public static final String SEND_PUISH_VERSION_PUBLISH ="{\"cmd\":\"push_version_publish\"}";
    public static final String SEND_POPUP = "{\"cmd\":\"popup_sn\",\"data\":\"%s\"}";

    @Autowired
    IotUtils iotUtils;

    @Autowired
    AppConfig appConfig;

    @Autowired
    RedisTemplate redisTemplate;

    //Plase replace with Redis
    public Map<String, CacheMessage> cache = new Hashtable<>();
    public Map<String, CacheMessage> getCache() {
        return cache;
    }

    public ReceiveUpload check(String rentboxSN) throws Exception {
        String key = "check:" + rentboxSN;
        byte[] data = sendPopupWait(key, rentboxSN, SEND_CHECK, 10);

        ReceiveUpload receiveUpload = new ReceiveUpload(data);
        return receiveUpload;
    }


    public ReceiveUpload checkAll(String rentboxSN) throws Exception {
        String key = "check:" + rentboxSN;
        byte[] data = sendPopupWait(key, rentboxSN, SEND_CHECK_ALL,  10);
        ReceiveUpload receiveUpload = new ReceiveUpload(data);
        return receiveUpload;
    }


    public ReceivePopupSN popup(String rentboxSN, String singleSN) throws Exception {
        String key = "popup_sn:" + rentboxSN;
        String message = String.format(SEND_POPUP, singleSN);
        byte[] data = sendPopupWait(key, rentboxSN, message,  15); //尝试发送2次，超时8秒

        ReceivePopupSN receivePopupSN = new ReceivePopupSN(data);
        return receivePopupSN;
    }


    public ReceivePopupSN popupByRandom(String rentboxSN, int minPower) throws Exception {
        //check
        ReceiveUpload receiveUpload = check(rentboxSN);
        Powerbank powerbank = receiveUpload.getPowerbankByRandom(minPower);
        if(powerbank == null){
            throw new Exception("NO Powerbank");
        }

        //popup
        ReceivePopupSN receivePopupSN = popup(rentboxSN, powerbank.getSnAsString());
        return receivePopupSN;
    }

    private byte[] sendPopupWait(String key, String rentboxSN, String message, int overSecound) throws Exception {
        this.checkOnlineStatus(rentboxSN);

        //PUT REDIS
        BoundValueOperations operations = redisTemplate.boundValueOps(key);
        operations.set(null, overSecound, TimeUnit.SECONDS);

        String topic = "/" + appConfig.getProductKey() + "/" + rentboxSN  + "/user/get";
        iotUtils.sendMsgAsync(appConfig.getProductKey(), topic, message, 1 );

        byte[] bytes = null;
        for(int i = 0; i < overSecound * 2; i ++){
            Thread.sleep(500);
            Object data = null;
            try {
                data = operations.get();
            }
            catch (Exception e){
                e.printStackTrace();
            }
            if(data != null && data instanceof byte[]){
                bytes = (byte[]) data;
                redisTemplate.boundValueOps(key).expire(-1, TimeUnit.MILLISECONDS);
                break;
            }
        }

        if(bytes == null){
            throw new Exception("Request Time Out");
        }

        return bytes;
    }

    public void checkOnlineStatus(String rentboxSN) throws Exception {
        DeviceOnline onlineStatus = iotUtils.getDeviceStatus(appConfig.getProductKey(), rentboxSN);
        if(!onlineStatus.name().equals("ONLINE")){
            throw new Exception("Device is Offline");
        }
    }





}
